package com.klikmee.sms.core.base.postman;

import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Date;

import org.apache.log4j.Logger;
import org.hibernate.cfg.NotYetImplementedException;

import com.klikmee.sms.core.commons.queues.EnqueueItemException;
import com.klikmee.sms.core.commons.queues.QueueItem;
import com.klikmee.sms.core.commons.queues.QueueManager;
import com.klikmee.sms.core.model.BulkMessage;
import com.klikmee.sms.core.model.IncomingMessage;
import com.klikmee.sms.core.model.OutgoingMessage;
import com.klikmee.sms.core.model.Service;

/**
 * Service message deliverer that relies on queueing mechanisms.
 * 
 * @author makcro
 * 
 */
public class QueueingServiceMessageDelivererImpl implements ServiceMessageDeliverer {

	/**
	 * Logger instance
	 */
	private Logger							logger	= Logger.getLogger( QueueingServiceMessageDelivererImpl.class );

	/**
	 * Queue manager for incoming messages that need to be delivered to services
	 */
	protected QueueManager<IncomingMessage>	incommingMessageQueueManager;	
	/**
	 * Number of hours to keep trying to deliver incoming message
	 */
	protected int							incomingMessageValidityPerionInMinutes;

	/**
	 * Queue manager for delivery reports that need to be delivered to services
	 */
	protected QueueManager<OutgoingMessage>	deliveryReportQueueManager;
	protected QueueManager<BulkMessage>		bulkDeliveryReportQueueManager;
	/**
	 * Number of hours to keep trying to deliver status report
	 */
	protected int							deliveryReportValidityPeriodInHours;

	/**
	 * This method initializes message deliverer.
	 * 
	 */
	public void init() {
		// start queue managers
		this.deliveryReportQueueManager.start();
		this.incommingMessageQueueManager.start();
		this.bulkDeliveryReportQueueManager.start();
		logger.info( MessageFormat.format( "QueueingServiceMessageDeliverer intialized, IM validity period [{0}] minutes, DR validity period [{1}] hours", incomingMessageValidityPerionInMinutes,
				deliveryReportValidityPeriodInHours ) );
	}

	@Override
	public boolean deliverMessage(IncomingMessage incomingMessage) {
		// create queue item with validity period
		QueueItem<IncomingMessage> queueItem = new QueueItem<IncomingMessage>( incomingMessage );
		// set items validity period
		Calendar currentTime = Calendar.getInstance();
		currentTime.add( Calendar.MINUTE, this.incomingMessageValidityPerionInMinutes );
		queueItem.setValidTo( currentTime.getTime() );

		try {
			this.incommingMessageQueueManager.enqueue( queueItem );
			logger.debug( MessageFormat.format( "Sucessfuly enqueued item [{0}]", queueItem ) );
			return true;
		}
		catch (EnqueueItemException e) {
			logger.fatal( MessageFormat.format( "Failed to enqueue incoming message {0}", incomingMessage ), e );
			return false;
		}

	}

	@Override
	public boolean forwardDeliveryReport(OutgoingMessage outgoingMessage) {
		// create queue item and set validity period
		QueueItem<OutgoingMessage> queueItem = new QueueItem<OutgoingMessage>( outgoingMessage );
		// set items validity period
		Calendar currentTime = Calendar.getInstance();
		currentTime.add( Calendar.HOUR_OF_DAY, this.deliveryReportValidityPeriodInHours );
		queueItem.setValidTo( currentTime.getTime() );

		try {
			this.deliveryReportQueueManager.enqueue( queueItem );
			logger.debug( MessageFormat.format( "Sucessfuly enqueued item [{0}]", queueItem ) );
			return true;
		}
		catch (EnqueueItemException e) {
			logger.fatal( MessageFormat.format( "Failed to enqueue delivery report [{0}]", outgoingMessage ), e );
			return false;
		}

	}

	@Override
	public boolean forwardDeliveryReport(BulkMessage bulkMessage) {
		// create queue item and set validity period
		QueueItem<BulkMessage> queueItem = new QueueItem<BulkMessage>( bulkMessage );
		// set items validity period
		Calendar currentTime = Calendar.getInstance();
		currentTime.add( Calendar.HOUR_OF_DAY, this.deliveryReportValidityPeriodInHours );
		queueItem.setValidTo( currentTime.getTime() );

		try {
			this.bulkDeliveryReportQueueManager.enqueue( queueItem );
			logger.debug( MessageFormat.format( "Sucessfuly enqueued item [{0}]", queueItem ) );
			return true;
		}
		catch (EnqueueItemException e) {
			logger.fatal( MessageFormat.format( "Failed to enqueue delivery report [{0}]", bulkMessage ), e );
			return false;
		}
	}

	@Override
	public boolean forwardSubscripitonRequest(Service service, String distributionListId, String msisdn, Date validTo) {
		throw new NotYetImplementedException( "Not implemented" );
	}

	public void shutDown() {
		// shut down queue managers
		this.incommingMessageQueueManager.stop();
		this.deliveryReportQueueManager.stop();
		this.bulkDeliveryReportQueueManager.stop();
		logger.info( "Queueing service message deliverer shutdown" );
	}

	public void setIncommingMessageQueueManager(QueueManager<IncomingMessage> incommingMessageQueueManager) {
		this.incommingMessageQueueManager = incommingMessageQueueManager;
	}

	public void setDeliveryReportQueueManager(QueueManager<OutgoingMessage> deliveryReportQueueManager) {
		this.deliveryReportQueueManager = deliveryReportQueueManager;
	}

	public void setDeliveryReportValidityPeriodInHours(int deliveryReportValidityPeriodInHours) {
		this.deliveryReportValidityPeriodInHours = deliveryReportValidityPeriodInHours;
	}

	public void setIncomingMessageValidityPerionInMinutes(int incomingMessageValidityPerionInMinutes) {
		this.incomingMessageValidityPerionInMinutes = incomingMessageValidityPerionInMinutes;
	}

	public QueueManager<BulkMessage> getBulkDeliveryReportQueueManager() {
		return bulkDeliveryReportQueueManager;
	}

	public void setBulkDeliveryReportQueueManager(QueueManager<BulkMessage> bulkDeliveryReportQueueManager) {
		this.bulkDeliveryReportQueueManager = bulkDeliveryReportQueueManager;
	}

}
